package com.google.code.dhillon;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Dialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
import android.widget.SimpleAdapter.ViewBinder;

import com.google.code.dhillon.util.Util;

public class ActivityUI extends ListActivity {
	private static final int DIALOG_LOADING = 0;
	private static final String KEY_ICON = "icon";
	private static final String KEY_LABEL = "label";
	private static final String KEY_STATUSES = "statuses";
	private static final String KEY_LINKS = "links";
	private static final String KEY_THUMBNAILS = "thumbnails";

	private EditText mSearch = null;
	private Button mSubmit = null;
	private ArrayList<String> mStatuses = null;
	private ArrayList<String> mYouTubeLinks = null;
	private ArrayList<Bitmap> mThumbnails = null;

	/** Called when the activity is first created. */
	@SuppressWarnings("unchecked")
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		if (savedInstanceState != null) {
			// restore state
			mStatuses = (ArrayList<String>) savedInstanceState.getSerializable(KEY_STATUSES);
			mYouTubeLinks = (ArrayList<String>) savedInstanceState.getSerializable(KEY_LINKS);
			mThumbnails = (ArrayList<Bitmap>) savedInstanceState.getSerializable(KEY_THUMBNAILS);

			updateListView();
		}

		// start searching when user presses enter
		mSearch = (EditText) findViewById(R.id.search);
		mSubmit = (Button) findViewById(R.id.search_button);
		mSubmit.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				// send to background task to find their twitter songs
				new DownloadTwitterFeed().execute(mSearch.getText());
				// hide the soft keyboard if used
				InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
				imm.hideSoftInputFromWindow(mSearch.getWindowToken(), 0);
			}
		});
	}

	// save any data you do not want to fetch again
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putSerializable(KEY_STATUSES, mStatuses);
		outState.putSerializable(KEY_LINKS, mYouTubeLinks);
		outState.putSerializable(KEY_THUMBNAILS, mThumbnails);
	}

	// send them to the youtube page on click
	@Override
	protected void onListItemClick(ListView l, View v, int position, long id) {
		super.onListItemClick(l, v, position, id);
		Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(mYouTubeLinks.get(position)));
		startActivity(i);
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		if (id == DIALOG_LOADING) {
			ProgressDialog dialog = new ProgressDialog(this);
			dialog.setMessage(getText(R.string.twitter_load));
			dialog.setIndeterminate(true);
			return dialog;
		}
		return null;
	}

	/** Create a simple adapter to show the thumbnail and tweet. */
	private void updateListView() {
		// create status rows
		List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();
		for (int i = 0; i < mStatuses.size(); i++) {
			Bitmap icon = mThumbnails.get(i);
			String label = mStatuses.get(i);

			Map<String, Object> row = new HashMap<String, Object>();
			row.put(KEY_ICON, icon);
			row.put(KEY_LABEL, label);
			rows.add(row);
		}
		String[] fromKeys = new String[] { KEY_ICON, KEY_LABEL };
		int[] toIds = new int[] { R.id.icon, R.id.text1 };

		// create an adapter to fill our listview with the statuses fetched
		// from twitter
		SimpleAdapter adapter = new SimpleAdapter(ActivityUI.this, rows, R.layout.icon_list_item,
				fromKeys, toIds);
		adapter.setViewBinder(new ViewBinder() {
			public boolean setViewValue(View view, Object data, String textRepresentation) {
				if (view instanceof ImageView) {
					ImageView iv = (ImageView) view;
					iv.setImageBitmap((Bitmap) data);
					return true;
				}
				return false;
			}
		});

		// attach to our listview
		setListAdapter(adapter);
	}

	// pass in the three generic types, we are interested in the first and last
	// which are parameters to doInBackground and onPostExecute
	private class DownloadTwitterFeed extends
			AsyncTask<CharSequence, Void, DownloadTwitterFeed.AsyncResult> {
		// result class
		class AsyncResult {
			ArrayList<String> statuses;
			ArrayList<String> youTubeLinks;
			ArrayList<Bitmap> youTubeThumbnails;
		}

		// runs on ui thread before background task
		@Override
		protected void onPreExecute() {
			showDialog(DIALOG_LOADING);
			super.onPreExecute();
		}

		// runs off the ui thread in the background
		@Override
		protected AsyncResult doInBackground(CharSequence... params) {
			String username = params[0] + ""; // convert to String
			ArrayList<String> statusTexts = new ArrayList<String>();
			ArrayList<String> youTubeLinks = new ArrayList<String>();
			ArrayList<Bitmap> youTubeThumbnails = new ArrayList<Bitmap>();
			// try to grab data from twitter, cancel on any error
			try {
				URL url = new URL("http://twitter.com/statuses/user_timeline/"
						+ URLEncoder.encode(username, "UTF-8") + ".json?count=200");
				String response = Util.convertStreamToString(url.openStream());

				JSONArray statuses = new JSONArray(response);
				for (int i = 0; i < statuses.length(); i++) {
					JSONObject status = statuses.getJSONObject(i);
					String statusText = status.getString("text");
					// do a case insensitive search for the nowplaying hashtag
					if (statusText.toLowerCase().contains("#nowplaying")) {
						// use the status update to find a youtube video
						// get rid of hashtags
						String keywords = statusText.replaceAll("#\\w+", "");
						url = new URL(
								"http://gdata.youtube.com/feeds/api/videos?alt=json&max-results=1&q="
										+ URLEncoder.encode(keywords, "UTF-8"));
						response = Util.convertStreamToString(url.openStream());

						JSONObject ytFeed = new JSONObject(response).getJSONObject("feed");
						// no entry key if it can't find a video
						if (ytFeed.has("entry") && ytFeed.getJSONArray("entry").length() > 0) {
							// found a video, choose the best match
							JSONObject entry = ytFeed.getJSONArray("entry").getJSONObject(0);

							String link = entry.getJSONArray("link").getJSONObject(0).getString(
									"href");

							String thumbnailUrl = entry.getJSONObject("media$group").getJSONArray(
									"media$thumbnail").getJSONObject(0).getString("url");
							Bitmap thumbnail = BitmapFactory.decodeStream(new URL(thumbnailUrl)
									.openStream());

							// add status, youtube link and thumbnail to
							// model
							statusTexts.add(statusText);
							youTubeLinks.add(link);
							youTubeThumbnails.add(thumbnail);
						}
					}
				}
			} catch (MalformedURLException e) { // bad url
				e.printStackTrace();
				cancel(false);
			} catch (IOException e) { // could not connect
				e.printStackTrace();
				cancel(false);
			} catch (JSONException e) { // bad response
				e.printStackTrace();
				cancel(false);
			}
			AsyncResult result = new AsyncResult();
			result.statuses = statusTexts;
			result.youTubeLinks = youTubeLinks;
			result.youTubeThumbnails = youTubeThumbnails;
			return result;
		}

		// runs on the ui thread when task is canceled
		@Override
		protected void onCancelled() {
			super.onCancelled();
			dismissDialog(DIALOG_LOADING);
			Toast.makeText(ActivityUI.this, getText(R.string.fetch_error), Toast.LENGTH_LONG)
					.show();
		}

		// runs on the ui thread after background task is completed
		protected void onPostExecute(AsyncResult result) {
			// update the models
			mStatuses = result.statuses;
			mYouTubeLinks = result.youTubeLinks;
			mThumbnails = result.youTubeThumbnails;

			updateListView();

			dismissDialog(DIALOG_LOADING);
		}
	}
}